/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package edu.yonsei.iwb.sdt.algorithm;

import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.vocabulary.OWL;
import com.hp.hpl.jena.vocabulary.RDF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.hp.hpl.jena.vocabulary.XSD;
import edu.yonsei.iwb.sdt.SDTLearner;
import edu.yonsei.iwb.sdt.SDTLearningType;
import edu.yonsei.iwb.sdt.datastructure.DataStore;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidate;
import edu.yonsei.iwb.sdt.datastructure.DecomposeCandidateSet;
import edu.yonsei.iwb.sdt.datastructure.TargetInstance;
import edu.yonsei.iwb.sdt.refinement.Refinement;
import edu.yonsei.iwb.sdt.ontology.ClassModel;
import edu.yonsei.iwb.sdt.ontology.PropertyArc;
import edu.yonsei.iwb.sdt.ontology.UncountedResources;
import edu.yonsei.iwb.sdt.ontology.UnitClassModel;
import edu.yonsei.iwb.sdt.refinement.RefinementType;
import edu.yonsei.iwb.sdt.refinement.ValueInfoOfDP;
import edu.yonsei.iwb.sdt.refinement.generator.CardinalityRestrictionRefinementMaker;
import edu.yonsei.iwb.sdt.refinement.generator.ConceptConstructorRefinementMaker;
import edu.yonsei.iwb.sdt.refinement.generator.ConjunctionRefinementMaker;
import edu.yonsei.iwb.sdt.refinement.generator.DisjunctionRefinementMaker;
import edu.yonsei.iwb.sdt.refinement.generator.DomainRestrictionRefinementMaker;
import edu.yonsei.iwb.sdt.refinement.generator.QualificationRefinementMaker;
import edu.yonsei.iwb.sdt.util.SDTLog;
import edu.yonsei.iwb.ts.TSSearch;
import edu.yonsei.iwb.ts.model.ObjectNode;
import edu.yonsei.iwb.ts.model.Triple;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author JDK
 */
public class DCSSearcher {

//    Vector refinementSet;
//    private Model model;
//    private ClassModel classmodel;
//    private int learningOption;
    public static int FLAGNUM = 0;
    private DataStore ds;
//    private Vector<Resource> instanceSet;

    public DCSSearcher(DataStore ds) {
//        this.classmodel = classmodel;
//        this.instanceSet = instanceSet;
//        this.ccr = new ConceptConstructorRefinementMaker(this.model);
//        this.crr = new CardinalityRestrictionRefinementMaker(this.model);
        
        this.ds = ds;
//        refinementSet = refinementset;
    }
        
    /**
     *
     * @param dcs SDT 분류를 위한 후보 집합
     * @param tiSet targetClass를 type으로 갖는 인스턴스의 집합
     * @param hisPAset centerClass 확장되는데 활용한 프로퍼티 집합
     * @return
     */
    public DecomposeCandidateSet searchDecomposeCandidateSet(DecomposeCandidateSet dcs, Vector<TargetInstance> tiSet, Vector<PropertyArc> hisPAset) throws IOException {
//        System.out.println("# Searching candidate refinements...");
        dcs.setHistoryPropertySet(hisPAset);

        String targetclass = dcs.getLastAddedTargetClass();
        if (!UncountedResources.SET.contains(targetclass)) {
            if (hisPAset.isEmpty()) {
                //find concept constructor refinement based decompose candidate
                this.getAtomicConceptApplBasedRefinement(dcs, targetclass, tiSet);
            }
            
            ArrayList<String> lastResourceSet = this.findLastPositionedResources(tiSet, hisPAset);
            Vector<PropertyArc> presentPAset = this.findConnectedObjectPropertyArcSet(lastResourceSet);
            
            dcs.setConnectedPropertySet(presentPAset);
            
//            System.out.println("++ Last Resource Set");
//            for (int i = 0; i < lastResourceSet.size(); i++) {
//                String get = lastResourceSet.get(i);
//                System.out.println(" + " + get);                
//            }
            
            if(SDTLearner.FEATURE_SELECTION_METHOD == SDTLearningType.FS1){
                this.getAtomicRoleBasedRefinement(dcs, tiSet, lastResourceSet, presentPAset, hisPAset);                
            }else if(SDTLearner.FEATURE_SELECTION_METHOD == SDTLearningType.FS2){
                // random select properties FS2
                Vector<PropertyArc> randomPAset = randomSelectionOfProperty(presentPAset);
                this.getAtomicRoleBasedRefinement(dcs, tiSet, lastResourceSet, randomPAset, hisPAset);
            }else{
//                for (int i = 0; i < presentPAset.size(); i++) {
//                    PropertyArc get = presentPAset.get(i);
//                    System.out.println(" - " + get.toString());
//                }
                this.getAtomicRoleBasedRefinement(dcs, tiSet, lastResourceSet, presentPAset, hisPAset);
            }
            
//            Vector<String> dtpset = ucm.getDatatypePropertySet();
            //find domain restriction refinement based decompose candidate
//            getDatatypeRoleBasedRefinement(dcs, instSet, dtpset, hisPAset);
        }

        while (true) {
            try {
                Thread.sleep(500);
                if (complete()) {
                    break;
                }
            } catch (InterruptedException ex) {
            }
        }
//        dcs.printDecomposeCandidateSet();
        SDTLog.log(SDTLog.DETAIL, "# Candidate Refinement Search is finished...\n");
        return dcs;
    }
    
    private Vector<PropertyArc> randomSelectionOfProperty(Vector<PropertyArc> paset){
        int pssize = paset.size();
        Random ran = new Random();
        int seedOfseed = ran.nextInt();
        Random ran2 = new Random(seedOfseed);
        
        int selectSize = (int)(SDTLearner.SELECTRATE * pssize);
        Vector<Integer> temp = new Vector();
        Vector<PropertyArc> selPAset = new Vector();
        
        if(pssize == 1){
            return paset;
        }           
        
        loop:
        while(true){
            int index = ran2.nextInt(pssize);
            if(!temp.contains(index)){
                temp.add(index);
            }            
                        
            if(temp.size() == selectSize){
                break loop;
            }
        }
        
        for (int i = 0; i < temp.size(); i++) {
            int index = temp.get(i);
            selPAset.add(paset.get(index));
        }        
        
        return selPAset;
    }
    
    public ArrayList<String> findLastPositionedResources(Vector<TargetInstance> tiset, Vector<PropertyArc> paset) throws IOException{
        
        ArrayList<String> firstResourceSet = new ArrayList<String>();
        for (int i = 0; i < tiset.size(); i++) {
            TargetInstance ti = tiset.get(i);
            firstResourceSet.add(ti.getURI());            
        }
        
        if(paset.isEmpty()){
            return firstResourceSet;
        }else{
            ArrayList<String> instanceSet = firstResourceSet;
            for (int i = 0; i < paset.size(); i++) {
                PropertyArc pa = paset.get(i);
                if(pa.getDirection()){
                    ArrayList<ObjectNode> onlist = TSSearch.listObjectResourceByORsubjectsAndProperty(instanceSet, pa.getProperty());

                    instanceSet = new ArrayList<String>();
                    for (int j = 0; j < onlist.size(); j++) {
                        ObjectNode on = onlist.get(j);
                        instanceSet.add(on.getValue());
                    }
                }else{
                    ArrayList<String> onlist = TSSearch.listSubjectResourceByORobjectsAndProperty(pa.getProperty(), instanceSet);
                    instanceSet = onlist;
                }            
            }
            return instanceSet;
        }
        
        
    }

    public Vector<PropertyArc> findConnectedObjectPropertyArcSet(ArrayList<String> instances) throws IOException {
        Vector<PropertyArc> result = new Vector<PropertyArc>();

        ArrayList<String> fpredicateSet = TSSearch.listPredicateResourceByORsubjects(instances);
        for (int i = 0; i < fpredicateSet.size(); i++) {
            String p = fpredicateSet.get(i);
            if(!this.ds.isExistInObjectPropertyList(p)){
                continue;
            }
            
            if (this.ds.isExistPropertyArc(p, UnitClassModel.FORWARD)) {
                PropertyArc fpa = this.ds.getPropertyArcByURI(p, UnitClassModel.FORWARD);
                result.add(fpa);
            } else {
                PropertyArc fpa = new PropertyArc(p, UnitClassModel.FORWARD);
                this.ds.setPropertyArcSet(p, fpa, UnitClassModel.FORWARD);
                result.add(fpa);
            }
        }

        ArrayList<String> bpredicateSet = TSSearch.listDistinctPredicateResourceByORobjects(instances);
        for (int i = 0; i < bpredicateSet.size(); i++) {
            String p = bpredicateSet.get(i);
            if(!this.ds.isExistInObjectPropertyList(p)){
                continue;
            }
            
            if (this.ds.isExistPropertyArc(p, UnitClassModel.BACKWARD)) {
                PropertyArc bpa = this.ds.getPropertyArcByURI(p, UnitClassModel.BACKWARD);
                result.add(bpa);
            } else {
                PropertyArc bpa = new PropertyArc(p, UnitClassModel.BACKWARD);
                this.ds.setPropertyArcSet(p, bpa, UnitClassModel.BACKWARD);
                result.add(bpa);
            }
        }
        return result;
    }

    private boolean complete() {
        if (DCSSearcher.FLAGNUM == 0) {
            return true;
        }
        return false;
    }

    /**
     * generate atomic concept based refinement
     *
     * @param dcs
     * @param targetclass
     * @param instSet
     * @throws IOException
     */
    private void getAtomicConceptApplBasedRefinement(DecomposeCandidateSet dcs, String targetclass, Vector<TargetInstance> instSet) throws IOException {
        ConceptConstructorRefinementMaker ccr = new ConceptConstructorRefinementMaker(instSet);
        ArrayList<String> classSet = TSSearch.listSubjectResource(RDFS.subClassOf.getURI(), targetclass);

        for (int i = 0; i < UncountedResources.SET.size(); i++) {
            String uri = UncountedResources.SET.get(i);
            if (classSet.contains(uri)) {
                classSet.remove(uri);
            }
        }

        if (this.checkAllDisjoint(classSet) && !classSet.isEmpty()) {
            Vector<Refinement> refset = ccr.refinementGenerator(classSet);
            if (refset.size() > 1) {
                dcs.add(new DecomposeCandidate(refset, RefinementType.CONCEPTCONSTRUCTOR));
            }
        } else {
            for (int j = 0; j < classSet.size(); j++) {
                String classname = classSet.get(j);
//                System.out.println("------------------  " + classname);
                Vector<Refinement> refset = ccr.refinementGenerator(classname);
                if (refset.size() >1) {
                    dcs.add(new DecomposeCandidate(refset, RefinementType.CONCEPTCONSTRUCTOR));
                }
            }

//            if (learningOption == SDTLearningType.USE_CONJUNCTION_AND_DISJUNCTION) {
            for (int k = 0; k < classSet.size() - 1; k++) {
                String cenclassname = classSet.get(k);
                for (int n = 1; n < classSet.size(); n++) {
                    String conclassname = classSet.get(n);
                    if (checkDisjointANDsubclass(cenclassname, conclassname)) {
                        DCSSearcher.FLAGNUM++;
                        new ConjunctionRefinementMaker(cenclassname, conclassname, instSet, dcs).start();

                        DCSSearcher.FLAGNUM++;
                        new DisjunctionRefinementMaker(cenclassname, conclassname, instSet, dcs).start();

                    }
                }
            }
//            }
        }
    }

    private Vector<String> getClassOfTargetInstances(Vector<TargetInstance> instanceSet) throws IOException {
        Vector<String> resultSet = new Vector();
        
        ArrayList<String> nivalue = new ArrayList();
        for (int i = 0; i < instanceSet.size(); i++) {
            TargetInstance instance = instanceSet.get(i);
            if(!nivalue.contains(instance.getURI())){
                nivalue.add(instance.getURI());
            }
        }
        
        ArrayList<ObjectNode> classSet = TSSearch.listObjectResourceByORsubjectsAndProperty(nivalue, RDF.type.toString());
        for (int i = 0; i < classSet.size(); i++) {
            String className = classSet.get(i).getValue();
            if (UncountedResources.SET.contains(className)) {
                continue;
            }

            ArrayList<String> subClassSet = TSSearch.listSubjectResource(RDFS.subClassOf.getURI(), className);
            for (int j = 0; j < subClassSet.size(); j++) {
                String subclass = subClassSet.get(j);
                if (!resultSet.contains(subclass)) {
                    if (!UncountedResources.SET.contains(subclass)) {
                        if (subclass.startsWith("http")) {
                            if (!subclass.equals(className)) {
                                resultSet.add(subclass);
                            }
                        }
                    }
                }
            }
        }
        return resultSet;
    }

    /**
     * find atomic role based refinements
     *
     * @param dcs
     * @param instSet
     * @param presentPAset
     * @param hisPAset
     */
    private void getAtomicRoleBasedRefinement(DecomposeCandidateSet dcs, Vector<TargetInstance> instSet, ArrayList<String> lastResourceSet, Vector<PropertyArc> presentPAset, Vector<PropertyArc> hisPAset) throws IOException {
        ObjectProperty:
        for (int i = 0; i < presentPAset.size(); i++) {
            PropertyArc pa = presentPAset.get(i);
            String property = pa.getProperty();

            if (!hisPAset.isEmpty()) {
                PropertyArc lastHistoryArc = hisPAset.lastElement();
                if (lastHistoryArc.getProperty().equals(property)) {
                    if (pa.getDirection() != lastHistoryArc.getDirection()) {
                        continue ObjectProperty;
                    }
                }
            }

            // Cardinality Restriction Refinement  
            Hashtable<String, Integer> valueNumTable = getBaseValueNumberTable(lastResourceSet, pa);
            if (!valueNumTable.isEmpty()) {
                Vector<Integer> stvSet = this.getStandardValueOfObjectProperty(valueNumTable, pa);
                for (int k = 0; k < stvSet.size(); k++) {
                    DCSSearcher.FLAGNUM++;
                    new CardinalityRestrictionRefinementMaker(pa, valueNumTable, stvSet.get(k), hisPAset, instSet, dcs).start();
                }

                //Qualification Refinement
                Vector<String> connClassSet = this.getConnectedClassesForQR(pa, lastResourceSet);
                for (int n = 0; n < connClassSet.size(); n++) {
                    DCSSearcher.FLAGNUM++;
                    new QualificationRefinementMaker(pa, connClassSet.get(n), hisPAset, instSet, dcs).start();
                }

//                if (learningOption == SDTLearningType.USE_CONJUNCTION_AND_DISJUNCTION) {
//                    for (int k = 0; k < connClassSet.size() - 1; k++) {
//                        for (int b = k + 1; b < connClassSet.size(); b++) {
//                            if (!this.checkDisjointANDsubclass(connClassSet.get(k), connClassSet.get(b))) {
//                                DCSSearcher.FLAGNUM++;
//                                new ConjunctionRefinementMaker(connClassSet.get(k), connClassSet.get(b), pa, hisPAset, instSet, dcs).start();
//                                DCSSearcher.FLAGNUM++;
//                                new DisjunctionRefinementMaker(connClassSet.get(k), connClassSet.get(b), pa, hisPAset, instSet, dcs).start();
//                            }
//                        }
//                    }
//                }

            }


        }
    }

    /**
     * find domain restriction refinements
     *
     * @param dcs
     * @param instSet
     * @param dtpset
     * @param hisPAset
     * @throws IOException
     */
    private void getDatatypeRoleBasedRefinement(DecomposeCandidateSet dcs, Vector<TargetInstance> instSet, Vector<String> dtpset, Vector<PropertyArc> hisPAset) throws IOException {
        for (int k = 0; k < dtpset.size(); k++) {
            String prop = dtpset.get(k);
            ValueInfoOfDP vio = this.getStandardValueOfDatatypeProperty(prop);
            if (vio != null) {
                int datatype = vio.getType();
                if (datatype == ValueInfoOfDP.BOOLEAN) {
                    DCSSearcher.FLAGNUM++;
                    new DomainRestrictionRefinementMaker(prop, vio, instSet, hisPAset, datatype, dcs).start();
                } else if (datatype == ValueInfoOfDP.DATARANGE) {
                    DCSSearcher.FLAGNUM++;
                    new DomainRestrictionRefinementMaker(prop, vio, instSet, hisPAset, datatype, dcs).start();
                } else {
                    Vector standards = vio.getStandard();
                    for (int i = 0; i < standards.size(); i++) {
                        Object st = standards.get(i);
                        DCSSearcher.FLAGNUM++;
                        new DomainRestrictionRefinementMaker(prop, vio, instSet, hisPAset, datatype, st, dcs).start();
                    }
                }
            }
        }

    }

    private Hashtable<String, Integer> getBaseValueNumberTable(ArrayList<String> lastResourceSet, PropertyArc pa) throws IOException {
        Hashtable<String, Integer> valueNumTable = new Hashtable();

        if (pa.getDirection()) {
            ArrayList<String> res = TSSearch.listSubjectResource(pa.getProperty());
            for (int i = 0; i < res.size(); i++) {
                String value = res.get(i);
                if (!lastResourceSet.contains(value)) {
                    continue;
                }

                if (!valueNumTable.containsKey(value)) {
                    valueNumTable.put(value, 1);
                } else {
                    int size = valueNumTable.get(value);
                    size++;
                    valueNumTable.put(value, size);
                }
            }
        } else {
            ArrayList<ObjectNode> ni = TSSearch.listObjectNode(pa.getProperty());
            for (int i = 0; i < ni.size(); i++) {
                ObjectNode on = ni.get(i);
                String value = on.getValue();
                if (!lastResourceSet.contains(value)) {
                    continue;
                }

                if (!valueNumTable.containsKey(value)) {
                    valueNumTable.put(value, 1);
                } else {
                    int size = valueNumTable.get(value);
                    size++;
                    valueNumTable.put(value, size);
                }
            }
        }
        return valueNumTable;
    }

    private Vector<Integer> getStandardValueOfObjectProperty(Hashtable<String, Integer> valueNumTable, PropertyArc pa) throws IOException {
//        if (SearchedPropertyStandards.contains(pa)) {
//            return SearchedPropertyStandards.get(pa);
//        } else {
        Vector<Integer> standard = new Vector<Integer>();
        standard.add(0);

        int highest = 0;
        Enumeration<String> values = valueNumTable.keys();
        while (values.hasMoreElements()) {
            String value = values.nextElement();
            int size = valueNumTable.get(value);
            if (highest < size) {
                highest = size;
            }
        }

        int lastStandard = highest / 2;
        if ((highest % 2) == 0) {
            if (!standard.contains(lastStandard)) {
                standard.add(lastStandard);
            }
        } else {
            lastStandard++;
            if (!standard.contains(lastStandard)) {
                standard.add(lastStandard);
            }
        }
        SearchedPropertyStandards.put(pa, standard);
        return standard;
//        }
    }

    private ValueInfoOfDP getStandardValueOfDatatypeProperty(String property) throws IOException {
        ValueInfoOfDP vio = new ValueInfoOfDP();


        ArrayList<ObjectNode> ni0 = TSSearch.listObjectNode(property, RDFS.range.getURI());
        for (int i = 0; i < ni0.size(); i++) {
            ObjectNode on = ni0.get(i);
            if (on.getValue().equals(XSD.xboolean.getURI())) {
                vio.setType(ValueInfoOfDP.BOOLEAN);
            } else if (on.getValue().equals(XSD.xint.getURI())) {
                vio.setType(ValueInfoOfDP.INT);
            } else if (on.getValue().equals(XSD.xstring.getURI())) {
                vio.setType(ValueInfoOfDP.STRING);
            } else if (on.getValue().equals(XSD.date.getURI())) {
                vio.setType(ValueInfoOfDP.DATE);
            } else if (on.getValue().equals(XSD.nonNegativeInteger.getURI())) {
                vio.setType(ValueInfoOfDP.INT);
            } else if (on.getValue().equals(XSD.positiveInteger.getURI())) {
                vio.setType(ValueInfoOfDP.INT);
            } else if (on.getValue().equals(XSD.integer.getURI())) {
                vio.setType(ValueInfoOfDP.INT);
            } else {
                ArrayList<Triple> st2 = TSSearch.listTriple(on.getValue(), RDF.type.getURI(), OWL.DataRange.getURI());
                if (!st2.isEmpty()) {
                    vio.setType(ValueInfoOfDP.DATARANGE);
                } else {
                    vio.setType(ValueInfoOfDP.STRING);
                }
            }
        }

        ArrayList<Triple> tripleSet = TSSearch.listTriple(null, property, null);
        for (int i = 0; i < tripleSet.size(); i++) {
            Triple tr = tripleSet.get(i);
            String subject = tr.getSubject();
            ObjectNode on = tr.getObject();
            String value = on.getValue();
            vio.put(value, on.getType());
            vio.putResourceAndValueTable(subject, value);
        }

        return vio;
    }

//    public Vector<String> getConnectedClasses(PropertyArc pa, int x) throws IOException {
//        return this.classmodel.getConnectedClass(pa.toString());
//    }

    public Vector<String> getConnectedClasses(PropertyArc pa) throws IOException {
        Vector<String> rangeSet = new Vector();
        String prop = pa.getProperty();

        if (pa.getDirection()) {
            ArrayList<ObjectNode> ni = TSSearch.listObjectNode(prop, RDFS.range.getURI());
            ArrayList<String> nivalue = new ArrayList();
            for (int i = 0; i < ni.size(); i++) {
                ObjectNode on = ni.get(i);
                String r = on.getValue();
                nivalue.add(r);
            }

            ArrayList<ObjectNode> ni2 = TSSearch.listObjectNode(prop, RDFS.subPropertyOf.getURI());
            for (int i = 0; i < ni2.size(); i++) {
                ObjectNode on = ni2.get(i);
                String superprop = on.getValue();
                ArrayList<ObjectNode> ni3 = TSSearch.listObjectNode(superprop, RDFS.range.getURI());
                for (int j = 0; j < ni3.size(); j++) {
                    ObjectNode on2 = ni3.get(j);
                    nivalue.add(on2.getValue());
                }
            }

            for (int i = 0; i < nivalue.size(); i++) {
                String r = nivalue.get(i);
                if (!UncountedResources.SET.contains(r)) {
                    if (!rangeSet.contains(r)) {
                        rangeSet.add(r);
                    }
                }
            }
        } else {
            ArrayList<String> nivalue = new ArrayList();
            ArrayList<ObjectNode> ni = TSSearch.listObjectNode(prop, RDFS.domain.getURI());
            for (int i = 0; i < ni.size(); i++) {
                ObjectNode on = ni.get(i);
                String r = on.getValue();
                nivalue.add(r);
            }

            ArrayList<ObjectNode> ni2 = TSSearch.listObjectNode(prop, RDFS.subPropertyOf.getURI());
            for (int i = 0; i < ni2.size(); i++) {
                ObjectNode on = ni2.get(i);
                String superprop = on.getValue();
                ArrayList<ObjectNode> ni3 = TSSearch.listObjectNode(superprop, RDFS.domain.getURI());
                for (int j = 0; j < ni3.size(); j++) {
                    ObjectNode on2 = ni3.get(j);
                    nivalue.add(on2.getValue());
                }
            }


            for (int i = 0; i < nivalue.size(); i++) {
//                ObjectNode on = ni.get(i);
                String r = nivalue.get(i);
                if (!UncountedResources.SET.contains(r)) {
                    if (!rangeSet.contains(r)) {
                        rangeSet.add(r);
                    }
                }
            }
        }
        return rangeSet;
    }

    public Vector<String> getConnectedClassesForQR(PropertyArc pa, ArrayList<String> lastResourceSet) throws IOException {
        Vector<String> resultSet = new Vector();
        String prop = pa.getProperty();

        if (pa.getDirection()) {
            ArrayList<ObjectNode> ni = TSSearch.listObjectResourceByORsubjectsAndProperty(lastResourceSet, prop);
            ArrayList<String> nivalue = new ArrayList();
            for (int i = 0; i < ni.size(); i++) {
                ObjectNode on = ni.get(i);
                String r = on.getValue();
                nivalue.add(r);
            }

            ArrayList<ObjectNode> classSet = TSSearch.listObjectResourceByORsubjectsAndProperty(nivalue, RDF.type.toString());

            for (int i = 0; i < classSet.size(); i++) {
                String className = classSet.get(i).getValue();
                if (UncountedResources.SET.contains(className)) {
                    continue;
                }

                ArrayList<String> subClassSet = TSSearch.listSubjectResource(RDFS.subClassOf.getURI(), className);
                for (int j = 0; j < subClassSet.size(); j++) {
                    String subclass = subClassSet.get(j);
                    if (!resultSet.contains(subclass)) {
                        if (!UncountedResources.SET.contains(subclass)) {
                            if (subclass.startsWith("http")) {
                                if (!subclass.equals(className)) {
                                    resultSet.add(subclass);
                                }
                            }
                        }
                    }
                }
            }

        } else {

            ArrayList<String> si = TSSearch.listSubjectResourceByORobjectsAndProperty(prop, lastResourceSet);
            ArrayList<String> sivalue = new ArrayList();
            for (int i = 0; i < si.size(); i++) {
                String r = si.get(i);
                sivalue.add(r);
            }

            ArrayList<ObjectNode> classSet = TSSearch.listObjectResourceByORsubjectsAndProperty(sivalue, RDF.type.toString());

            ArrayList<ObjectNode> ni2 = TSSearch.listObjectNode(prop, RDFS.subPropertyOf.getURI());
            for (int i = 0; i < ni2.size(); i++) {
                ObjectNode on = ni2.get(i);
                String superprop = on.getValue();
                ArrayList<ObjectNode> ni3 = TSSearch.listObjectNode(superprop, RDFS.domain.getURI());
                for (int j = 0; j < ni3.size(); j++) {
                    ObjectNode on2 = ni3.get(j);
                    sivalue.add(on2.getValue());
                }
            }

            for (int i = 0; i < classSet.size(); i++) {
                String className = classSet.get(i).getValue();
                if (UncountedResources.SET.contains(className)) {
                    continue;
                }

                ArrayList<String> subClassSet = TSSearch.listSubjectResource(RDFS.subClassOf.getURI(), className);
                for (int j = 0; j < subClassSet.size(); j++) {
                    String subclass = subClassSet.get(j);
                    if (!resultSet.contains(subclass)) {
                        if (!UncountedResources.SET.contains(subclass)) {
                            if (subclass.startsWith("http")) {
                                if (!subclass.equals(className)) {
                                    resultSet.add(subclass);
                                }
                            }
                        }
                    }
                }
            }
        }
        return resultSet;
    }

    /**
     *
     * @param v 클래스 집합
     * @return v에 포함된 클래스들이 서로 Disjoint 한지 여부
     */
    private boolean checkAllDisjoint(ArrayList<String> v) throws IOException {
//        boolean tf = false;

        for (int i = 0; i < v.size() - 1; i++) {
            String r1 = v.get(i);
            for (int j = 1; j < v.size(); j++) {
                String r2 = v.get(j);
                ArrayList<Triple> t = TSSearch.listTriple(r1, OWL.disjointWith.getURI(), r2);
                if (t.isEmpty()) {
                    return false;
                }
            }
        }
        return true;
    }

    private boolean checkDisjointANDsubclass(String cen, String con) throws IOException {
        ArrayList<Triple> st = TSSearch.listTriple(con, OWL.disjointWith.getURI(), cen);
        if (st.isEmpty()) {
            return true;
        }
        return false;
    }
}
